#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>	
#include <fcntl.h>
#include <unistd.h>
#include <wait.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <linux/if.h>
#include <resolv.h>
#include <arpa/nameser.h>
#include <sys/mman.h>
#include <errno.h>
#include <setjmp.h>
#include <time.h>
#include <sys/time.h>
#include <signal.h>
#include <pthread.h>

#define RET_FAILURE (-1)
#define RET_SUCCESS  0

#define PLOG(level,format,args...) \
	     do{printf("[%s]",#level);printf(format,##args);}while(0)

static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
static sigjmp_buf jmpbuf;
static volatile sig_atomic_t canjump;
static void alarm_handle(int signo)
{
	if(canjump == 0)
		return;
	canjump = 0;
	siglongjmp(jmpbuf,1);
}
/**
 * gethostbyname process one domain to ip address
 * @param[in] name the host name,domain name
 * @param[in,out] ip  the buff to store the host ip
 * @ret RET_SUCCESS -- ok, RET_FAILURE -- error or failed
 */
int gethostbyname_proc2(char *name,char *ip)
{
	int ret = RET_SUCCESS;
	struct hostent *host = NULL;
	int timeout = 5;

	if(name == NULL || ip == NULL)
	{
		PLOG(ERR,"invalid params!\n");
		return RET_FAILURE;
	}

	pthread_mutex_lock(&lock);
	sigset_t mask,oldmask;
	sigemptyset(&mask);
	sigaddset(&mask,SIGALRM);
	pthread_sigmask(SIG_UNBLOCK,&mask,&oldmask);
#if 1
	signal(SIGALRM, alarm_handle);
	alarm(timeout);
//	printf("+++++++++++++call again 22222222 +++++++\n");
	if(sigsetjmp(jmpbuf,1)!=0)
	{
		PLOG(ERR,"gethostbyname timeout\n");
		alarm(0);
		signal(SIGALRM,SIG_IGN);
		pthread_mutex_unlock(&lock);
		pthread_sigmask(SIG_SETMASK,&oldmask,NULL);
		return RET_FAILURE;
	}
	canjump = 1; /* sigsetjmp() is ok */
#endif
	res_init(); /* clear dns_cache */
	host = gethostbyname(name);
	int i = 0;
	while(1)
	{
		printf(">>>i=%d\n",i++);//host = NULL;
		sleep(1);
	}
	/* cancel signal handle if return */
	alarm(0); // cancel timer
	signal(SIGALRM,SIG_IGN);

	//printf("+++++++++++++call again 333333333+++++++\n");
	if (host == NULL) 
	{// use h_errno not errno variable
		PLOG(ERR, "get host %s err:%s!\n", name, hstrerror(h_errno));
		ret = RET_FAILURE;
	}
	else
	{// only get the first ipv4 addr if host has many ipv4 addrs
		inet_ntop(AF_INET,(struct in_addr *)host->h_addr,ip,INET_ADDRSTRLEN);
		PLOG(DBG, "gethostbyname %s success,ip:%s!\n",name,ip);
		ret = RET_SUCCESS;
	}
	pthread_sigmask(SIG_SETMASK,&oldmask,NULL);
	pthread_mutex_unlock(&lock);
	return ret;
}

void *get_host_addr(void *arg)
{
	int ret = 0;
	char name[32] = "www.baidu.com";
	char ip[16]={0};
	while(1)
	{
		printf("++++++++++++++[%s]time1 = %lu +++++++++++\n",(char*)arg,time(NULL));
		ret = gethostbyname_proc2(name,ip);
		printf("++++++++++++++[%s]time2 = %lu +++++++++++\n",(char*)arg,time(NULL));
		usleep(100000);
	}
	return (void*)ret;
}

int main(int argc, char *argv[])
{
	int ret = 0;
	char name[32] = "www.baidu.com";
	char ip[16]={0};
	pthread_t tid1,tid2;
	sigset_t mask,oldmask;

	sigemptyset(&mask);
	sigaddset(&mask,SIGALRM);
	pthread_sigmask(SIG_BLOCK,&mask,&oldmask);

	pthread_create(&tid1,NULL,get_host_addr,"T_11");
	pthread_create(&tid2,NULL,get_host_addr,"T_22");
	//
#if 0	
	while(1)
	{
		get_host_addr("main");
	}
#endif

	pthread_join(tid1,NULL);
	pthread_join(tid2,NULL);
	
	sigprocmask(SIG_SETMASK,&oldmask,NULL);

	return ret;
}

